﻿using SeguriGasesERP.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;

namespace SeguriGasesERP.Controllers
{
    [Authorize(Roles = "Administrador")]
    public class InventarioController : Controller
    {
        public struct Cambio
        {

            public int IDentrada;
            public decimal CantidadOriginal;
            public decimal CantidadNueva;
            public int idProducto;
            public int idSucursal;
            public String NombreSucursal;
            public String NombreProducto;

            public Cambio(int IDentrada, decimal CantidadOriginal, decimal CantidadNueva, int idProducto, int idSucursal, String NombreSucursal, String NombreProducto)
            {
                this.IDentrada = IDentrada;
                this.CantidadOriginal = CantidadOriginal;
                this.CantidadNueva = CantidadNueva;
                this.idProducto = idProducto;
                this.idSucursal = idSucursal;
                this.NombreProducto = NombreProducto;
                this.NombreSucursal = NombreSucursal;
            }
        };
        
        //
        // GET: /Inventario/

        public ActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Index(HttpPostedFileBase file)
        {
            
            if (file == null || file.ContentLength <= 0)
                return RedirectToAction("Error", 1);

            string path = this.SaveUploadedFile(file);
            List<ProductoSucursal> inventarioImportado = this.ImportarExistencias(path);
            List<Cambio> Cambios = this.ProcesarExistencias(inventarioImportado);
            TempData["cambios"] = Cambios;
            return RedirectToAction("Confirmacion");
        }

        /// <summary>
        /// Metodo que presenta los detalles de cambio previo a escribir en la base de datos
        /// </summary>
        /// <returns></returns>
        public ActionResult Confirmacion()
        {
            List<Cambio> Cambios =  (List<Cambio>) TempData["cambios"];
            ViewBag.Cambios = Cambios;
            TempData["cambios"] = Cambios;
            return View();
        }

        [HttpPost]
        public ActionResult Confirmacion(List<Cambio> cambios)
        {
            cambios = (List<Cambio>)TempData["cambios"];
            //TODO: Procesar los cambios
            this.GuardarAjustes(cambios);

            return RedirectToAction("Exito", cambios);
        }

        public ActionResult Exito()
        {
            return View();
        }

        #region Helpper Methods

        /// <summary>
        /// Guarda el archivo subido en el servidor para ser utilizado
        /// </summary>
        /// <param name="file">Archivo subido</param>
        /// <returns></returns>
        private string SaveUploadedFile(HttpPostedFileBase file)
        {
            string basePath = Path.GetTempPath();
            DirectoryInfo di;
            if (!Directory.Exists(basePath))
                di = Directory.CreateDirectory(basePath);

            var fileName = Path.GetFileName(file.FileName);
            
            var path = Path.Combine(basePath, fileName);
            file.SaveAs(path);

            return path;
        }

        /// <summary>
        /// Metodo que escribe los datos en la BD
        /// </summary>
        /// <param name="cambios"> Lista de cambios a escribir</param>
        /// <returns></returns>
        private bool GuardarAjustes(List<Cambio> cambios)
        {
            using (SeguriGasesEntities db = new SeguriGasesEntities())
            {
                foreach (var item in cambios)
                {
                    ProductoSucursal prodSuc = db.ProductosSucursal.Find(item.IDentrada);
                    if (prodSuc == null)
                    {
                        return false;
                    }

                    prodSuc.cantidad = item.CantidadNueva;
                }

                db.SaveChanges();
                return true;
            }
        }

        /// <summary>
        /// Metodo que busca las diferencias y prepara la lista de cambios para ser actualizado en la base de datos
        /// </summary>
        /// <param name="inventarioImportado">Informacion importada desde el archivo</param>
        /// <returns></returns>
        private List<Cambio> ProcesarExistencias(List<ProductoSucursal> inventarioImportado)
        {
            List < ProductoSucursal >  inventarioActual = this.GetInventarioGeneral();
            List<Cambio> cambios = new List<Cambio>();
            this.ExportarInventario(inventarioActual);

            foreach (ProductoSucursal item in inventarioImportado)
            {
                ProductoSucursal original = inventarioActual.Find(x => x.ID == item.ID);
                if (original == null)
                    return null;

                //Si no hay cambios en la cantidad, lo brincamos
                if (original.cantidad == item.cantidad)
                    continue;

                Cambio cambio = new Cambio();
                cambio.IDentrada = original.ID;
                cambio.CantidadOriginal = original.cantidad;
                cambio.CantidadNueva = item.cantidad;
                cambio.idProducto = original.IdProducto;
                cambio.idSucursal = original.IdSucursal;

                if (original.Sucursal == null)
                {
                    using (SeguriGasesEntities db = new SeguriGasesEntities())
                    {
                        cambio.NombreSucursal = db.Sucursales.Find(cambio.idSucursal).Nombre;
                    }
                }
                else
                    cambio.NombreSucursal = original.Sucursal.Nombre;

                if(original.Producto == null)
                {
                    using (SeguriGasesEntities db = new SeguriGasesEntities())
                    {
                        cambio.NombreProducto = db.Productos.Find(cambio.idProducto).Nombre;
                    }
                }
                else
                    cambio.NombreProducto = original.Producto.Nombre;

                cambios.Add(cambio);
            }
            return cambios;
        }

        /// <summary>
        /// Metodo que lee y parsea el archivo subido por el usuario
        /// </summary>
        /// <param name="filePath">Ruta del archivo a leer</param>
        /// <returns></returns>
        private List<ProductoSucursal> ImportarExistencias(string filePath)
        {
            List<ProductoSucursal> InventarioImportado = new List<ProductoSucursal>();
            string[] lines;

            try
            {

                lines = System.IO.File.ReadAllLines(filePath);
            }
            catch (System.IO.IOException)
            {
                return null;
            }

            foreach (string line in lines)
            {
                ProductoSucursal prodSuc = new ProductoSucursal(); 
                string[] datos = line.Split('\t');
                int id;
                decimal cantidad;

                //Posiciones
                // 0 - ID
                // 1 - Sucursal
                // 2 - Clave Producto
                // 3 - Producto
                // 4 - Existencia

                if (datos.Length != 5)
                {
                    //El formato no corresponde con el esperado
                    return null;
                }

                //Convertimos el id a entero
                if (!int.TryParse(datos[0], out id))
                {
                    //No pudimos convertir el ID
                    return null;
                }

                //Convertimos la cantidad a decimal
                if (!decimal.TryParse(datos[4], out cantidad))
                {
                    //No pudimos convertir la cantidad
                    return null;
                }

                prodSuc.ID = id;
                prodSuc.cantidad = cantidad;

                InventarioImportado.Add(prodSuc);
            }
            return InventarioImportado;
        }

        /// <summary>
        /// Exporta una copia del estado actual del inventario antes de actualizarlo
        /// </summary>
        /// <param name="Inventario"> Inventario actual </param>
        public void ExportarInventario(List<ProductoSucursal> Inventario)
        {            
            using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\Inventario\" + DateTime.Now.Day + "" + DateTime.Now.Month + "" + DateTime.Now.Year + "_" + DateTime.Now.Hour + "" + DateTime.Now.Minute + "" + DateTime.Now.Second + ".txt"))
            {
                foreach (var entrada in Inventario)
                {
                    StringBuilder sb = new StringBuilder();
                    sb.Append(entrada.ID);
                    sb.Append("\t");
                    sb.Append(entrada.cantidad);
                    sb.Append("\t");
                    sb.Append(entrada.IdProducto);
                    sb.Append("\t");
                    sb.Append(entrada.IdSucursal);
                    sb.Append("\t");

                    file.Write(sb);
                }
            }
        }
        
        /// <summary>
        /// Esta funcion regresa una lista con las existencias de cada producto en cada sucursal
        /// </summary>
        /// <returns> Lista de producto por sucursal </returns>
        public List<ProductoSucursal> GetInventarioGeneral()
        {
              using (SeguriGasesEntities db = new SeguriGasesEntities())
              {
                List<ProductoSucursal> Inventario = db.ProductosSucursal.Include("Producto").Include("Sucursal").OrderBy(p => p.Producto.Nombre).ToList();
                return Inventario;
              }
        }

        #endregion

    }
}
